OPC Studio User's Guide and Reference
Connection handling
Concepts > Common Concepts > Common Operation Model > Connection handling
In This Topic

Connection-less model

OPC (Client-Server model) is inherently stateful. For starters, connections to OPC servers are long-living entities with rich internal state, and other objects in OPC model such as OPC groups have internal state too. OPC Studio products hide most of the OPC’s stateful nature by providing a connection-less (stateless) interface for OPC tasks.

From an application perspective (such as with Excel Connector), or client developer perspective (when using OPC Data Client), this transformation from a stateful to a stateless model is actually one of the biggest advantages you gain by using products based on OPC Studio. There are several advantages to a stateless model from the perspective of your application. Here are the most important of them:

Connection-less model in OPC Data Client

The internal state of OPC Data Client components (including e.g. the connections to OPC servers) outlives the lifetime of the individual instances of the main EasyDAClientEasyAEClient or EasyUAClient object.  You can therefore create an instance of this object as many times as you wish, without incurring performance penalty to OPC communications. This characteristic comes extremely handy in programming server-side Web applications and similar scenarios: You can implement your code on page level, and make OPC requests from the page code itself. The OPC connections will outlive the page round-trips (if this was not the case, the OPC server would become bogged down quickly).

Automatic connection maintenance

Products based on OPC Studio automatically establish a connection to the target OPC server whenever it is needed. The connection is maintained at least for a duration of the operation requested. For example, if your code or application makes an OPC "read" from a specific target OPC server, and an underlying OPC Studio component is not yet connected to it, it will connect first. After the read operation is finished, the connection is kept open for certain time, called the "hold period". This allows subsequent operations to reuse the connection that is already open. If the connection is no longer necessary, it is automatically closed.

Any OPC subscription keeps the connection to the target OPC server open at least for the duration of the subscription. In addition, if you use subscribe in any of OPC Studio products, you declare a "standing" request to subscribe and stay subscribed, until you explicitly unsubscribe. If the connection breaks for any reason, or if it is not possible to connect at the time of the initial subscribe, OPC Studio components will keep trying reestablish the connection as long as you are subscribed.

Automatic connection sharing

Inside a process (more precisely, a .NET AppDomain, but in most cases that is equivalent to a process), OPC Studio components keep just one connection to each target OPC server, regardless of whether multiple requests for operations on that server came from just one client object, or multiple client objects. This way, your code does have to bother with efficiency concerns related to the fact that multiple connections from the same OPC client to the same OPC server are normally unnecessary and create a performance problem.

In some (relatively rare) cases you may want to disable the connection sharing. This can be achieved using Isolated Clients and Subscribers.

Dormant sessions

(This paragraph applies only to OPC UA)

OPC Studio components keep data related to a session in memory for some time after the session has been closed ("dormant session"). This allows faster reconnection later. The period for which the session data is kept in memory after the session is closed is configurable by the UASmartClientSessionParameters.DormancyPeriod property. The maximum count of sessions that can be kept in the dormant state is configurable in the UASmartClientEngineParameters.MaximumDormantSessions property.

Example

.NET

// This example shows that either a single client object, or multiple client objects can be used to read values from two
// servers.
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
// OPC client and subscriber examples in C# on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-CSharp .
// Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
// a commercial license in order to use Online Forums, and we reply to every post.

using System;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.OperationModel;

namespace UADocExamples._EasyUAClient
{
    partial class ReadValue
    {
        public static void MultipleServers()
        {
            // Define which servers we will work with.
            UAEndpointDescriptor endpointDescriptor1 =
                "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer";
            // or "http://opcua.demo-this.com:51211/UA/SampleServer" (currently not supported)
            // or "https://opcua.demo-this.com:51212/UA/SampleServer/"
            UAEndpointDescriptor endpointDescriptor2 =
                "opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer";



            // Part 1: Use a single client object.
            // This demonstrates the fact that the client objects do *not* represent connections to individual servers.
            // Instead, they are able to maintain connections to multiple servers internally. API method calls on the client
            // object include the server's endpoint descriptor in their arguments, so you can specify a different endpoint
            // with each operation.
            Console.WriteLine();

            // Instantiate the client object
            var client = new EasyUAClient();

            Console.WriteLine("Obtaining values of nodes using a single client object...");
            object value1, value2;
            try
            {
                // The node Id we are reading returns the product name of the server.
                value1 = client.ReadValue(endpointDescriptor1, "nsu=http://opcfoundation.org/UA/ ;i=2261");
                value2 = client.ReadValue(endpointDescriptor2, "nsu=http://opcfoundation.org/UA/ ;i=2261");
                // Note: For efficiency (reading from the two servers in parallel), it would be better to use the
                // ReadMultipleValues method here, but this example is made for code clarity.
            }
            catch (UAException uaException)
            {
                Console.WriteLine("*** Failure: {0}", uaException.GetBaseException().Message);
                return;
            }

            // Display results
            Console.WriteLine("value1: {0}", value1);
            Console.WriteLine("value2: {0}", value2);



            // Part 2: Use multiple client objects.
            // This demonstrates the fact that it is also possible to use multiple client objects, and on the OPC side, the
            // behavior will be the same as if you had used a single client object. Multiple client objects consume somewhat
            // more resources on the client side, but they come handy if, for example,
            // - you cannot easily pass around the single pre-created client object to various parts in your code, or
            // - you are using subscriptions, and you want to hook separate event handlers for different purposes, or
            // - you need to set something in the instance parameters of the client object differently for different
            // connections.
            Console.WriteLine();

            // Instantiate the client objects.
            var client1 = new EasyUAClient();
            var client2 = new EasyUAClient();

            Console.WriteLine("Obtaining values of nodes using multiple client objects...");
            try
            {
                // The node Id we are reading returns the product name of the server.
                value1 = client1.ReadValue(endpointDescriptor1, "nsu=http://opcfoundation.org/UA/ ;i=2261");
                value2 = client2.ReadValue(endpointDescriptor2, "nsu=http://opcfoundation.org/UA/ ;i=2261");
            }
            catch (UAException uaException)
            {
                Console.WriteLine("*** Failure: {0}", uaException.GetBaseException().Message);
                return;
            }

            // Display results
            Console.WriteLine("value1: {0}", value1);
            Console.WriteLine("value2: {0}", value2);



            // Example output:
            //
            //Obtaining values of nodes using a single client object...
            //value1: OPC UA SDK Samples
            //value2: OPC UA Workshop Samples
            //
            //Obtaining values of nodes using multiple client objects...
            //value1: OPC UA SDK Samples
            //value2: OPC UA Workshop Samples
        }
    }
}
' This example shows that either a single client object, or multiple client objects can be used to read values from two
' servers.
'
' Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
' OPC client and subscriber examples in VB.NET on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-VBNET .
' Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
' a commercial license in order to use Online Forums, and we reply to every post.

Imports Newtonsoft.Json.Linq
Imports OpcLabs.EasyOpc.UA
Imports OpcLabs.EasyOpc.UA.OperationModel

Namespace _EasyUAClient
    Partial Friend Class ReadValue
        Public Shared Sub MultipleServers()

            ' Define which server we will work with.
            Dim endpointDescriptor1 As UAEndpointDescriptor =
                    "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer"
            ' or "http://opcua.demo-this.com:51211/UA/SampleServer" (currently not supported)
            ' or "https://opcua.demo-this.com:51212/UA/SampleServer/"
            Dim endpointDescriptor2 As UAEndpointDescriptor =
                    "opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer"


            ' Part 1: Use a single client object.
            ' This demonstrates the fact that the client objects do *not* represent connections to individual servers.
            ' Instead, they are able to maintain connections to multiple servers internally. API method calls on the client
            ' object include the server's endpoint descriptor in their arguments, so you can specify a different endpoint
            ' with each operation.
            Console.WriteLine()

            ' Instantiate the client object
            Dim client = New EasyUAClient()

            Console.WriteLine("Obtaining values of nodes using a single client object...")
            ' Obtain value of a node
            Dim value1 As Object
            Dim value2 As Object
            Try
                ' The node Id we are reading returns the product name of the server.
                value1 = client.ReadValue(endpointDescriptor1, "nsu=http://opcfoundation.org/UA/ ;i=2261")
                value2 = client.ReadValue(endpointDescriptor2, "nsu=http://opcfoundation.org/UA/ ;i=2261")
                ' Note: For efficiency(reading from the two servers in parallel), it would be better to use the
                ' ReadMultipleValues method here, but this example is made for code clarity.
            Catch uaException As UAException
                Console.WriteLine("*** Failure: {0}", uaException.GetBaseException.Message)
                Exit Sub
            End Try

            ' Display results
            Console.WriteLine("value1: {0}", value1)
            Console.WriteLine("value2: {0}", value2)


            ' Part 2: Use multiple client objects.
            ' This demonstrates the fact that it is also possible to use multiple client objects, and on the OPC side, the
            ' behavior will be the same as if you had used a single client object. Multiple client objects consume somewhat
            ' more resources on the client side, but they come handy if, for example,
            ' - you cannot easily pass around the single pre-created client object to various parts in your code, or
            ' - you are using subscriptions, and you want to hook separate event handlers for different purposes, or
            ' - you need to set something in the instance parameters of the client object differently for different
            ' connections.
            Console.WriteLine()

            ' Instantiate the client objects.
            Dim client1 = New EasyUAClient()
            Dim client2 = New EasyUAClient()

            Console.WriteLine("Obtaining values of nodes using multiple client objects...")
            Try
                ' The node Id we are reading returns the product name of the server.
                value1 = client1.ReadValue(endpointDescriptor1, "nsu=http://opcfoundation.org/UA/ ;i=2261")
                value2 = client2.ReadValue(endpointDescriptor2, "nsu=http://opcfoundation.org/UA/ ;i=2261")
            Catch uaException As UAException
                Console.WriteLine("*** Failure: {0}", uaException.GetBaseException.Message)
                Exit Sub
            End Try

            ' Display results
            Console.WriteLine("value1: {0}", value1)
            Console.WriteLine("value2: {0}", value2)


            ' Example output
            '
            'Obtaining values of nodes using a single client object...
            'value1: Opc UA SDK Samples
            'value2: Opc UA Workshop Samples
            '
            'Obtaining values of nodes using multiple client objects...
            'value1: Opc UA SDK Samples
            'value2: Opc UA Workshop Samples
        End Sub
    End Class
End Namespace

Python

# This example shows that either a single client object, or multiple client objects can be used to read values from two
# servers.
#
# Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
# OPC client and subscriber examples in Python on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-Python .
# Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
# a commercial license in order to use Online Forums, and we reply to every post.
# The QuickOPC package is needed. Install it using "pip install opclabs_quickopc".
import opclabs_quickopc

# Import .NET namespaces.
from OpcLabs.EasyOpc.UA import *
from OpcLabs.EasyOpc.UA.OperationModel import *


# Define which servers we will work with.
endpointDescriptor1 = UAEndpointDescriptor('opc.tcp://opcua.demo-this.com:51210/UA/SampleServer')
# or 'http://opcua.demo-this.com:51211/UA/SampleServer' (currently not supported)
# or 'https://opcua.demo-this.com:51212/UA/SampleServer/'
endpointDescriptor2 = UAEndpointDescriptor('opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer')


# Part 1: Use a single client object.
# This demonstrates the fact that the client objects do *not* represent connections to individual servers.
# Instead, they are able to maintain connections to multiple servers internally. API method calls on the client
# object include the server's endpoint descriptor in their arguments, so you can specify a different endpoint
# with each operation.
print()

# Instantiate the client object.
client = EasyUAClient()

print('Obtaining values of nodes using a single client object...')
try:
    # The node Id we are reading returns the product name of the server.
    value1 = IEasyUAClientExtension.ReadValue(client,
                                              endpointDescriptor1,
                                              UANodeDescriptor('nsu=http://opcfoundation.org/UA/ ;i=2261'))
    value2 = IEasyUAClientExtension.ReadValue(client,
                                              endpointDescriptor2,
                                              UANodeDescriptor('nsu=http://opcfoundation.org/UA/ ;i=2261'))
except UAException as uaException:
    print('*** Failure: ' + uaException.GetBaseException().Message)
    exit()

# Display results.
print('value1: ', value1, sep='')
print('value2: ', value2, sep='')


# Part 2: Use multiple client objects.
# This demonstrates the fact that it is also possible to use multiple client objects, and on the OPC side, the
# behavior will be the same as if you had used a single client object. Multiple client objects consume somewhat
# more resources on the client side, but they come handy if, for example,
# - you cannot easily pass around the single pre-created client object to various parts in your code, or
# - you are using subscriptions, and you want to hook separate event handlers for different purposes, or
# - you need to set something in the instance parameters of the client object differently for different
# connections.
print()

# Instantiate the client objects.
client1 = EasyUAClient()
client2 = EasyUAClient()

print('Obtaining values of nodes using multiple client objects...')
try:
    # The node Id we are reading returns the product name of the server.
    value1 = IEasyUAClientExtension.ReadValue(client1,
                                              endpointDescriptor1,
                                              UANodeDescriptor('nsu=http://opcfoundation.org/UA/ ;i=2261'))
    value2 = IEasyUAClientExtension.ReadValue(client2,
                                              endpointDescriptor2,
                                              UANodeDescriptor('nsu=http://opcfoundation.org/UA/ ;i=2261'))
except UAException as uaException:
    print('*** Failure: ' + uaException.GetBaseException().Message)
    exit()

# Display results.
print('value1: ', value1, sep='')
print('value2: ', value2, sep='')


print()
print('Finished.')

 

 

See Also

Fundamentals

Introduction

Examples - Client OPC Unified Architecture